-- -------------------------------------------------------------------------
-- UI/theme.lua
-- Theme Management System
-- -------------------------------------------------------------------------

local theme = {}
local json_lib = require("ClickUl.Lib.json")
local debugger = nil
local lang = nil
local io_queue = nil

-- [Translation Helper]
local function _T(text)
    if _G and _G._T then
        return _G._T(text)
    end
    if lang then
        if lang.get then return lang.get(text) end
        if lang.get_text then return lang.get_text(text) end
    end
    return text
end

-- [Debug Helper]
local function log_debug(msg)
    if debugger and debugger.debug then
        debugger.debug("[Theme]", tostring(msg))
    end
end

local function get_base_dir()
    local base = ".\\"
    if paths and paths.script then
        base = paths.script
    end

    local last_char = string.sub(base, -1)
    if last_char ~= "\\" and last_char ~= "/" then
        base = base .. "\\"
    end

    return base .. "ClickUl\\"
end

local function get_themes_dir()
    return get_base_dir() .. "Themes\\"
end

local CONFIG_FILENAME = "Default.json"
local CURRENT_THEME_FILE = "current_theme.txt"

local math_floor = math.floor
local type = type
local pairs = pairs

local function safe_close(f)
    if not f then return end
    if type(f.close) == "function" then
        pcall(f.close, f)
    elseif type(f.Close) == "function" then
        pcall(f.Close, f)
    end
    -- Some APIs auto-close, so we don't error if no close method exists
end

function theme.get_base_dir()
    return get_base_dir()
end

local function encode_json(tbl)
    local ok, result = pcall(json_lib.encode_pretty, tbl, "  ")
    if ok and result and #result > 0 then return result end
    return nil, result
end

local function decode_json(str)
    local ok, result = pcall(json_lib.decode, str)
    if ok and result then return result end
    return nil, result
end

local cached_default_config = nil

local function create_default_config()
    local cfg = {
        bg_image_enabled = false,
        bg_image_file = "",
        bg_image_opacity = 255,
        sidebar_icons = {},
        notification_icons = {
            ["Success"] = "logo.png",
            ["Warning"] = "logo.png",
            ["Error"] = "logo.png",
            ["Info"] = "logo.png",
            ["Spectator"] = "logo.png",
            ["Join"] = "logo.png",
            ["Leave"] = "logo.png",
            ["Modder"] = "logo.png",
            ["Script Event"] = "logo.png",
            ["Network Event"] = "logo.png",
            ["Protection"] = "logo.png",
            ["Player Manager"] = "logo.png"
        },
        notification_position = "bottom_right",
         base = {
             -- Window Layout
             x = 901, y = 287,
             w = 760, h = 600,
             header_h = 24,
             sidebar_w = 64,
             padding = 20,
             item_h = 40,
             button_h = 40,
             slider_h = 55,
             item_spacing = 8,

             -- Corner Rounding (individual corners)
             window_rounding_tl = 8,  -- top-left
             window_rounding_tr = 8,  -- top-right
             window_rounding_bl = 8,  -- bottom-left
             window_rounding_br = 8,  -- bottom-right
             header_rounding_tl = 8,
             header_rounding_tr = 8,

            -- Fonts
            font_header = 17,
            font_tab = 15,
            font_subtab = 13,
            font_group = 14,
            font_widget = 14,
            font_small = 13,

            -- Slider
            slider_height = 5,
            slider_track_offset = 30,
            slider_extra_height = 20,

            -- Scrollbar
            scrollbar_width = 6,
            scrollbar_thumb_min = 20,
            scrollbar_hit_width = 16,

            -- Checkbox
            checkbox_width = 40,
            checkbox_height = 22,
            checkbox_knob_size = 18,
            checkbox_knob_offset = 2,
            checkbox_track_rounding = 11,
            checkbox_knob_rounding = 4,
            checkbox_use_toggle_style = false,  -- false=box style, true=toggle switch style

            -- Toggle
            toggle_width = 40,
            toggle_height = 22,
            toggle_knob_size = 18,
            toggle_knob_offset = 2,
            toggle_track_rounding = 11,
            toggle_knob_rounding = 9,

            -- Widget General
            widget_rounding = 6,
            widget_text_padding = 10,

             -- Group
             group_header_height = 36,
             group_content_padding = 10,
             group_spacing = 8,
             group_rounding = 8,

            -- Sidebar
            sidebar_btn_margin = 6,
            sidebar_icon_size = 32,
            sidebar_btn_spacing = 4,
            sidebar_btn_rounding = 6,

             -- SubTabBar
             subtab_height = 30,
             subtab_gap = 8,
             subtab_rounding = 6,
             subtab_spacing_after = 6,

            -- InlineTabBar
            inline_tab_height = 24,
            inline_tab_gap = 4,
            inline_tab_indicator_height = 2,

            -- Separator
            separator_height = 1,
            separator_margin = 8,

            -- ProgressBar
            progress_height = 8,
            progress_rounding = 4,

            -- DualColumn
            dual_column_gap = 8,
            dual_column_bottom_margin = 10,

            -- Combo
            combo_max_visible = 5,
            combo_dropdown_gap = 4,
            combo_thumb_min = 20,

            -- Scroll
            scroll_speed = 60,
            scroll_group_speed = 40,

            -- Animation
            click_anim_duration = 0.25,
            click_anim_alpha = 40,

            -- Content Area
            content_padding_y = 8,
            window_content_offset = 2,
            divider_width = 1,
            divider_padding = 8,

            -- Overlay
            overlay_font_size = 14,
            overlay_radius = 4,
            overlay_offset_x = -10,  -- Horizontal offset from menu edge

             -- Notification
             notif_radius = 8,
             notif_title_size = 17,
             notif_message_size = 14,
             notif_spacing = 8,
             notif_margin_x = 20,
             notif_margin_y = 20,
             notif_max_count = 12,
             notif_width = 320,
             notif_padding = 6,
             notif_icon_size = 32,
             notif_min_height = 60,
             notif_duration = 5.0,
             -- notif_slide_offset removed (deprecated - now uses dynamic calculation)
             notif_anim_speed_in = 4.0,
             notif_anim_stack_speed = 15.0,
             notif_flash_cooldown = 1.5,
             -- [PERF V5] Animation enhancements
             notif_exit_speed_multiplier = 1.5,  -- Exit animation speed multiplier
             notif_flash_decay_speed = 6.0,      -- Exponential decay speed (higher = faster)
             -- [PERF V5] Time bar (progress indicator)
             notif_time_bar_enabled = true,
             notif_time_bar_height = 2,
             notif_time_bar_opacity = 180,

            -- ColorPicker
            color_preview_height = 12,
            color_preview_rounding = 4,

            -- Row Layout
            row_gap = 8,

            -- Menu Hints Overlay (keyboard shortcuts window)
            menu_hints_font_size = 16,
            menu_hints_offset_y = 2,  -- Distance below main window
            menu_hints_height = 30,
            menu_hints_padding = 10,
            menu_hints_rounding = 8,
        },
        current = {},
        colors = {
            ["Window Background"] = {r=24, g=24, b=29, a=250},
            ["Sidebar Background"] = {r=18, g=18, b=22, a=255},
            ["Header Background"] = {r=14, g=14, b=18, a=255},
            ["Background Tint"] = {r=255, g=255, b=255, a=255},
            ["Header Text"] = {r=255, g=255, b=255, a=255},
            ["Text Primary"] = {r=240, g=240, b=245, a=255},
            ["Text Secondary"] = {r=140, g=140, b=155, a=255},
            ["Accent"] = {r=114, g=137, b=218, a=255},
            ["Group Background"] = {r=32, g=32, b=38, a=220},
            ["Group Header Text"] = {r=200, g=200, b=210, a=255},
            ["Group Header Line"] = {r=60, g=60, b=70, a=255},
            ["Widget Background"] = {r=40, g=40, b=46, a=255},
            ["Widget Hover"] = {r=55, g=55, b=62, a=255},
            ["Player Selected Background"] = {r=60, g=65, b=80, a=255},
            ["Checkbox Active"] = {r=114, g=137, b=218, a=255},
            ["Checkbox Inactive"] = {r=55, g=55, b=62, a=255},
            ["Toggle Active"] = {r=114, g=137, b=218, a=255},
            ["Toggle Inactive"] = {r=70, g=72, b=80, a=255},
            ["Knob"] = {r=255, g=255, b=255, a=255},  -- Legacy, kept for compatibility
            ["Knob Active"] = {r=255, g=255, b=255, a=255},
            ["Knob Inactive"] = {r=140, g=140, b=140, a=255},
            ["Slider Empty"] = {r=25, g=25, b=30, a=255},
            ["Slider Filled"] = {r=114, g=137, b=218, a=255},
            ["Slider Filled Hover"] = {r=170, g=190, b=255, a=255},
            ["Slider Background"] = {r=40, g=40, b=46, a=255},
            ["Slider Background Hover"] = {r=55, g=55, b=62, a=255},
            ["Combo Background"] = {r=32, g=32, b=38, a=255},
            ["Combo Highlight"] = {r=114, g=137, b=218, a=100},
            -- Level 1 TAB (Sidebar main tabs) colors
            ["Tab Background"] = {r=28, g=28, b=34, a=255},              -- Inactive background
            ["Tab Background Hover"] = {r=40, g=40, b=48, a=255},        -- Hover background
            ["Tab Background Active"] = {r=114, g=137, b=218, a=255},    -- Active background
            ["Tab Text Inactive"] = {r=100, g=100, b=110, a=255},        -- Inactive text
            ["Tab Text Active"] = {r=255, g=255, b=255, a=255},          -- Active text
            ["Tab Indicator"] = {r=114, g=137, b=218, a=255},            -- Indicator (unused)
            -- Level 2 TAB (SubTab subtabs) colors
            ["Subtab Background"] = {r=32, g=32, b=38, a=255},           -- Inactive background
            ["Subtab Hover"] = {r=45, g=45, b=52, a=255},                -- Hover background
            ["Subtab Active"] = {r=114, g=137, b=218, a=255},            -- Active background
            ["Subtab Text Inactive"] = {r=160, g=160, b=170, a=255},     -- Inactive text
            ["Subtab Text Active"] = {r=255, g=255, b=255, a=255},       -- Active text
            ["Scrollbar"] = {r=114, g=137, b=218, a=150},
            ["Scrollbar Hover"] = {r=160, g=180, b=255, a=255},
            ["Notification Background"] = {r=50, g=55, b=65, a=200},  -- Default/Info notification
            ["Notification Success"] = {r=75, g=181, b=67, a=180},
            ["Notification Warning"] = {r=250, g=170, b=50, a=180},
            ["Notification Error"] = {r=220, g=53, b=69, a=180},
            ["Notification Spectator"] = {r=220, g=53, b=69, a=180},
            ["Notification Flash"] = {r=255, g=255, b=255, a=150},
            ["Notification Join"] = {r=90, g=160, b=255, a=180},
            ["Notification Leave"] = {r=250, g=170, b=50, a=180},
            ["Notification Modder"] = {r=220, g=53, b=69, a=180},
            ["Notification Script Event"] = {r=220, g=53, b=69, a=180},
            ["Notification Network Event"] = {r=220, g=53, b=69, a=180},
            ["Notification Protection"] = {r=220, g=53, b=69, a=180},
            ["Notification Player Manager"] = {r=100, g=220, b=150, a=180},
            ["Overlay Background"] = {r=24, g=24, b=29, a=250},
            ["Overlay Text"] = {r=255, g=255, b=255, a=255},
            ["Overlay Divider"] = {r=100, g=150, b=255, a=255},
            -- Individual Tag Colors
            ["Tag ME"] = {r=90, g=220, b=90, a=255},
            ["Tag Friend"] = {r=90, g=160, b=255, a=255},
            ["Tag Modder"] = {r=255, g=90, b=90, a=255},
            ["Tag God"] = {r=255, g=60, b=60, a=255},
            ["Tag Spectating"] = {r=190, g=100, b=255, a=255},
            ["Tag Modded"] = {r=200, g=80, b=255, a=255},
            ["Tag Bounty"] = {r=255, g=140, b=40, a=255},
            ["Tag Script Host"] = {r=255, g=215, b=0, a=255},
            ["Tag Session Host"] = {r=255, g=230, b=80, a=255},
            ["Tag Vehicle"] = {r=255, g=200, b=60, a=255},
            ["Tag Next Host"] = {r=255, g=110, b=200, a=255},
            ["Tag CEO"] = {r=80, g=240, b=240, a=255},
            ["Tag Dead"] = {r=140, g=140, b=150, a=255},
            ["Tag Interior"] = {r=160, g=160, b=170, a=255},
            ["Tag Controller"] = {r=150, g=150, b=160, a=255},
            -- InlineTabBar
            ["Inline Tab Active"] = {r=114, g=137, b=218, a=255},
            ["Inline Tab Inactive"] = {r=140, g=140, b=155, a=255},
            ["Inline Tab Indicator"] = {r=114, g=137, b=218, a=255},
            -- Separator
            ["Separator Line"] = {r=60, g=60, b=70, a=255},
            ["Separator Text"] = {r=100, g=100, b=110, a=255},
            -- ProgressBar
            ["Progress Background"] = {r=40, g=40, b=46, a=255},
            ["Progress Fill"] = {r=114, g=137, b=218, a=255},
            -- Menu Hints Overlay
            ["Menu Hints Background"] = {r=24, g=24, b=29, a=250},
            ["Menu Hints Text"] = {r=240, g=240, b=245, a=255},
        }
    }

    for k,v in pairs(cfg.base) do
        cfg.current[k] = v
    end

    return cfg
end

local function get_default_config()
    if not cached_default_config then
        cached_default_config = create_default_config()
    end
    return cached_default_config
end

function theme.init(_, debug_lib, lang_lib)
    debugger = debug_lib
    lang = lang_lib
    -- First parameter kept for API compatibility (previously json_lib, now using native json)

    if debugger then debugger.info("Theme system initializing") end
    if not theme.data then theme.reset() end
end

function theme.reset()
    theme.data = create_default_config()
end

function theme.save()
    -- Lazy load io_queue to avoid circular dependency
    if not io_queue then
        local ok, result = pcall(require, "ClickUl.Lib.io_queue")
        if ok then io_queue = result end
    end

    -- If io_queue available, use deferred save
    if io_queue then
        io_queue.queue_save(function()
            theme.save_immediate()
        end, "theme")
        return true
    end

    -- Fallback to immediate save
    return theme.save_immediate()
end

function theme.save_immediate()
    if debugger then debugger.mark_start("theme_save") end
    log_debug("Starting theme.save()...")

    if not json_lib then
        log_debug("Save error: JSON lib missing")
        if debugger then debugger.error("Theme save failed: JSON lib missing") end
        return false
    end

    local dir_path = get_themes_dir()
    local full_path = dir_path .. CONFIG_FILENAME

    if dirs and dirs.create then
        local ok, err = pcall(dirs.create, dir_path)
        if not ok and debugger and debugger.debug then
            debugger.debug("Failed to create directory", { path = dir_path, error = tostring(err) })
        end
    end

    local save_data = {
        bg_image_enabled = theme.data.bg_image_enabled,
        bg_image_file = theme.data.bg_image_file or "",
        bg_image_opacity = theme.data.bg_image_opacity or 255,
        sidebar_icons = theme.data.sidebar_icons or {},
        notification_icons = theme.data.notification_icons or {},
        notification_position = theme.data.notification_position or "bottom_right",
        base = theme.data.base,
        colors = theme.data.colors
    }

    local content, enc_err = encode_json(save_data)
    if not content then
        log_debug("Save error: JSON Encode failed - " .. tostring(enc_err))
        return false
    end

    if file and file.open then
        local f = nil
        local ok, result = pcall(function()
            f = file.open(full_path, {create_if_not_exists=true, append=false})
            if f and (f.valid == nil or f.valid) then
                f.text = content
                return true
            end
            return false
        end)
        if f then safe_close(f) end

        if ok and result then
            log_debug("Native save success.")
            if debugger then
                debugger.mark_end("theme_save")
                debugger.info("Theme saved successfully")
            end
            return true
        end

        log_debug("Save error: Native file.open failed - " .. tostring(result))
        if debugger then debugger.error("Theme save failed: file.open failed", {error = result}) end
        return false
    end

    log_debug("Save error: File API missing")
    if debugger then debugger.error("Theme save failed: file API missing") end
    return false
end

function theme.load()
    if debugger then debugger.mark_start("theme_load") end
    log_debug("Starting theme.load()...")
    if not json_lib then return false end

    local dir_path = get_themes_dir()
    local full_path = dir_path .. CONFIG_FILENAME
    local content = nil

    if file and file.open then
        local ok, result = pcall(function()
            if file.exists(full_path) then
                local f = file.open(full_path, {create_if_not_exists=false, append=false})
                if f and f.valid then
                    local text = f.text
                    safe_close(f)
                    return text
                end
            end
            return nil
        end)

        if ok then
            content = result
        elseif debugger then
            debugger.debug("[Theme] Native file read failed", {error = result})
        end
    end

    if not content and debugger then
        debugger.debug("[Theme] File read failed or file API missing")
    end

    if not content or string.len(content) < 2 then
        theme.save()
        return false
    end

    local decoded, dec_err = decode_json(content)
    if decoded then
        if decoded.bg_image_enabled ~= nil then
            if type(decoded.bg_image_enabled) == "number" then
                theme.data.bg_image_enabled = (decoded.bg_image_enabled == 1)
            else
                theme.data.bg_image_enabled = decoded.bg_image_enabled
            end
        end

        if decoded.bg_image_file then theme.data.bg_image_file = decoded.bg_image_file end
        if decoded.bg_image_opacity then theme.data.bg_image_opacity = decoded.bg_image_opacity end

        if decoded.sidebar_icons and type(decoded.sidebar_icons) == "table" then
            theme.data.sidebar_icons = decoded.sidebar_icons
        end

        if decoded.notification_icons and type(decoded.notification_icons) == "table" then
            -- Merge with defaults to ensure new icon keys are included
            local defaults = get_default_config().notification_icons
            for k, v in pairs(defaults) do
                if decoded.notification_icons[k] == nil then
                    decoded.notification_icons[k] = v
                end
            end
            theme.data.notification_icons = decoded.notification_icons
        else
            local defaults = get_default_config()
            theme.data.notification_icons = defaults.notification_icons
        end

        if decoded.notification_position and type(decoded.notification_position) == "string" then
            theme.data.notification_position = decoded.notification_position
        else
            theme.data.notification_position = "bottom_right"
        end

        if decoded.base then
            local defaults = get_default_config().base
            for k, v in pairs(defaults) do
                if decoded.base[k] ~= nil then
                    theme.data.base[k] = tonumber(decoded.base[k]) or decoded.base[k]
                else
                    theme.data.base[k] = v
                end
            end

            for k, v in pairs(theme.data.base) do
                theme.data.current[k] = v
            end
        end

        if decoded.colors then
            -- [Migration] Ensure new color keys from defaults exist
            local defaults = get_default_config().colors
            for k, v in pairs(defaults) do
                if theme.data.colors[k] == nil then
                    theme.data.colors[k] = v
                end
            end

            for k, v in pairs(theme.data.colors) do
                local c = decoded.colors[k]
                if c and type(c) == "table" then
                    theme.data.colors[k] = {
                        r = tonumber(c.r) or v.r,
                        g = tonumber(c.g) or v.g,
                        b = tonumber(c.b) or v.b,
                        a = tonumber(c.a) or v.a
                    }
                end
            end

            -- [Migration] Fix Toggle Inactive if it's still the old blue color (same as Toggle Active)
            local ti = theme.data.colors["Toggle Inactive"]
            local ta = theme.data.colors["Toggle Active"]
            if ti and ta and ti.r == ta.r and ti.g == ta.g and ti.b == ta.b then
                -- Old theme had Toggle Inactive same as Toggle Active, update to new gray
                theme.data.colors["Toggle Inactive"] = {r=70, g=72, b=80, a=255}
                log_debug("Migrated Toggle Inactive color from blue to gray")
            end
        end

        log_debug("Default theme loaded successfully.")
        if debugger then
            debugger.info("Default theme loaded successfully")
        end

        -- Check if there's a different theme selected
        local current_name = theme.get_current_theme_name()
        if current_name and current_name ~= "" and current_name ~= "Default" then
            log_debug("Loading saved theme: " .. current_name)
            local load_ok = theme.load_theme(current_name)
            if load_ok then
                if debugger then
                    debugger.mark_end("theme_load")
                    debugger.info("Saved theme loaded: " .. current_name)
                end
                return true
            else
                log_debug("Failed to load saved theme, using Default")
                if debugger then debugger.warn("Failed to load saved theme: " .. current_name) end
            end
        end

        if debugger then debugger.mark_end("theme_load") end
        return true
    end

    log_debug("JSON Decode failed: " .. tostring(dec_err))
    if debugger then
        debugger.error("Theme load failed: JSON decode error", dec_err)
        debugger.mark_end("theme_load")
    end
    return false
end

-- -------------------------------------------------------------------------
-- Multi-Theme System
-- -------------------------------------------------------------------------

function theme.get_current_theme_name()
    local path = get_themes_dir() .. CURRENT_THEME_FILE

    if file and file.open and file.exists then
        local ok, result = pcall(function()
            if file.exists(path) then
                local f = file.open(path, {create_if_not_exists=false, append=false})
                if f and f.valid then
                    local name = f.text
                    safe_close(f)
                    return name
                end
            end
            return "Default"
        end)
        if ok then return result end
    end

    if debugger then
        debugger.debug("[Theme] Current theme read failed or file API missing", {path = path})
    end
    return "Default"
end

function theme.set_current_theme_name(name)
    local path = get_themes_dir() .. CURRENT_THEME_FILE

    if file and file.open then
        local ok, result = pcall(function()
            local f = file.open(path, {create_if_not_exists=true, append=false})
            if f then
                f.text = name
                safe_close(f)
                return true
            end
            return false
        end)
        if ok and result then return true end
    end

    if debugger then
        debugger.warn("[Theme] Failed to save current theme name", {path = path})
    end
    return false
end

function theme.list_themes()
    local themes = {"Default"}

    if not dirs or not dirs.list then return themes end

    local themes_path = get_themes_dir()

    if dirs.create then
        local ok, err = pcall(dirs.create, themes_path)
        if not ok and debugger then
            debugger.debug("[Theme] Failed to create Themes directory", {error = err})
        end
    end

    local ok, files = pcall(dirs.list, themes_path, "json")
    if ok and files then
        for _, f in ipairs(files) do
            local name = f:match("([^\\]+)%.json$") or f:match("([^/]+)%.json$")
            if name and name ~= "clickui_theme" then
                table.insert(themes, name)
            end
        end
    end

    return themes
end

function theme.save_as(theme_name)
    if not theme_name or theme_name == "" or theme_name == "Default" then
        return false, _T("Invalid theme name")
    end

    if not json_lib then
        return false, _T("JSON lib missing")
    end

    local themes_path = get_themes_dir()
    local full_path = themes_path .. theme_name .. ".json"

    if dirs and dirs.create then
        local ok, err = pcall(dirs.create, themes_path)
        if not ok and debugger then
            debugger.debug("[Theme] Failed to create Themes directory", {error = err})
        end
    end

    local save_data = {
        bg_image_enabled = theme.data.bg_image_enabled,
        bg_image_file = theme.data.bg_image_file or "",
        bg_image_opacity = theme.data.bg_image_opacity or 255,
        sidebar_icons = theme.data.sidebar_icons or {},
        notification_icons = theme.data.notification_icons or {},
        notification_position = theme.data.notification_position or "bottom_right",
        base = theme.data.base,
        colors = theme.data.colors
    }

    local content, enc_err = encode_json(save_data)
    if not content then
        return false, _T("JSON encode failed") .. ": " .. tostring(enc_err)
    end

    if file and file.open then
        local ok, result = pcall(function()
            local f = file.open(full_path, {create_if_not_exists=true, append=false})
            if f and (f.valid == nil or f.valid) then
                f.text = content
                safe_close(f)
                return true
            end
            return false
        end)

        if ok and result then
            theme.set_current_theme_name(theme_name)
            if debugger then debugger.info("Theme saved as: " .. theme_name) end
            return true
        end

        return false, _T("File write failed") .. ": " .. tostring(result)
    end

    return false, _T("File API missing")
end

function theme.load_theme(theme_name)
    if not theme_name or theme_name == "" then
        return false, _T("Invalid theme name")
    end

    if theme_name == "Default" then
        local result = theme.load()
        if result then
            theme.set_current_theme_name("Default")
        end
        return result
    end

    if not json_lib then return false, _T("JSON lib missing") end

    local themes_path = get_themes_dir()
    local full_path = themes_path .. theme_name .. ".json"
    local content = nil

    if file and file.open and file.exists then
        local ok, result = pcall(function()
            if file.exists(full_path) then
                local f = file.open(full_path, {create_if_not_exists=false, append=false})
                if f and f.valid then
                    local text = f.text
                    safe_close(f)
                    return text
                end
            end
            return nil
        end)

        if ok then
            content = result
        end
    end

    if not content and debugger then
        debugger.debug("[Theme] Theme read failed or file API missing", {path = full_path})
    end

    if not content or string.len(content) < 2 then
        return false, _T("Theme file not found or empty")
    end

    local decoded, dec_err = decode_json(content)
    if not decoded then
        return false, _T("JSON decode failed") .. ": " .. tostring(dec_err)
    end

    if decoded.bg_image_enabled ~= nil then
        if type(decoded.bg_image_enabled) == "number" then
            theme.data.bg_image_enabled = (decoded.bg_image_enabled == 1)
        else
            theme.data.bg_image_enabled = decoded.bg_image_enabled
        end
    end

    if decoded.bg_image_file then theme.data.bg_image_file = decoded.bg_image_file end
    if decoded.bg_image_opacity then theme.data.bg_image_opacity = decoded.bg_image_opacity end

    if decoded.sidebar_icons and type(decoded.sidebar_icons) == "table" then
        theme.data.sidebar_icons = decoded.sidebar_icons
    end

    if decoded.notification_icons and type(decoded.notification_icons) == "table" then
        -- Merge with defaults to ensure new icon keys are included
        local defaults = get_default_config().notification_icons
        for k, v in pairs(defaults) do
            if decoded.notification_icons[k] == nil then
                decoded.notification_icons[k] = v
            end
        end
        theme.data.notification_icons = decoded.notification_icons
    end

    if decoded.notification_position and type(decoded.notification_position) == "string" then
        theme.data.notification_position = decoded.notification_position
    end

    if decoded.base then
        local defaults = get_default_config().base
        for k, v in pairs(defaults) do
            if decoded.base[k] ~= nil then
                theme.data.base[k] = tonumber(decoded.base[k]) or decoded.base[k]
            else
                theme.data.base[k] = v
            end
        end

        for k, v in pairs(theme.data.base) do
            theme.data.current[k] = v
        end
    end

    if decoded.colors then
        -- [Migration] Ensure new color keys from defaults exist
        local defaults = get_default_config().colors
        for k, v in pairs(defaults) do
            if theme.data.colors[k] == nil then
                theme.data.colors[k] = v
            end
        end

        for k, v in pairs(theme.data.colors) do
            local c = decoded.colors[k]
            if c and type(c) == "table" then
                theme.data.colors[k] = {
                    r = tonumber(c.r) or v.r,
                    g = tonumber(c.g) or v.g,
                    b = tonumber(c.b) or v.b,
                    a = tonumber(c.a) or v.a
                }
            end
        end

        -- [Migration] Fix Toggle Inactive if it's still the old blue color (same as Toggle Active)
        local ti = theme.data.colors["Toggle Inactive"]
        local ta = theme.data.colors["Toggle Active"]
        if ti and ta and ti.r == ta.r and ti.g == ta.g and ti.b == ta.b then
            -- Old theme had Toggle Inactive same as Toggle Active, update to new gray
            theme.data.colors["Toggle Inactive"] = {r=70, g=72, b=80, a=255}
            log_debug("Migrated Toggle Inactive color from blue to gray")
        end
    end

    theme.set_current_theme_name(theme_name)
    if debugger then debugger.info("Theme loaded: " .. theme_name) end
    return true
end

return theme
